﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Options;
using RuoVea.EventBus;
using RuoVea.ExDto;
using RuoVea.ExEnum;
using RuoVea.ExFilter.Config;
using RuoVea.ExLog;
using RuoVea.ExUtil;
using System.ComponentModel;
using System.Diagnostics;
using System.Security.Claims;
using System.Text;
using UAParser;

namespace RuoVea.ExFilter;
/// <summary>
/// 全局日志记录 请求日志拦截
/// RequestActionFilter
/// </summary>
public class ActionFilter : IAsyncActionFilter, IOrderedFilter
{
    private readonly IEventPublisher _eventPublisher;
    private readonly List<GlobleActionModel> _globleActionModels;

    /// <summary>
    /// 构造
    /// </summary>
    /// <param name="eventPublisher"></param>
    /// <param name="globleActionModels"></param>
    public ActionFilter(IEventPublisher eventPublisher, IOptions<List<GlobleActionModel>> globleActionModels)
    {
        _eventPublisher = eventPublisher;
        _globleActionModels = globleActionModels.Value;
        if (_globleActionModels == null || _globleActionModels.Count == 0)
            _globleActionModels = ExFilterConfigs.FilterOptions.GlobleActionModels;
    }
    /// <summary>
    /// 过滤器排序
    /// </summary>
    internal const int FilterOrder = 8888;

    /// <summary>
    /// 排序属性
    /// </summary>
    public int Order => FilterOrder;

    /// <summary>
    /// 执行 Action 并获取结果
    /// </summary>
    /// <param name="context">ActionExecutingContext</param>
    /// <param name="next">ActionExecutionDelegate</param>
    /// <returns>无</returns>
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        // 执行 Action 并获取结果
        var actionContext = await next();

        // 获取控制器信息
        var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;

        if (ExFilterConfigs.FilterOptions.IsDbug)
        {
            var httpContext = context.HttpContext;
            var httpRequest = httpContext.Request;

            var sw = new Stopwatch();
            sw.Start();
            string actionArguments = string.Empty;
            try { actionArguments = context.ActionArguments.Json2Str(); } catch { }
            sw.Stop();

            // 判断是否请求成功（没有异常就是请求成功）
            var isRequestSucceed = actionContext.Exception == null;
            string? userAgent=httpContext.Request?.Headers["User-Agent"];

            ClientInfo clent = null;
            if(userAgent.NotNullOrWhiteSpace())
                clent= Parser.GetDefault().Parse(userAgent);

            var descAtt = Attribute.GetCustomAttribute(actionDescriptor.MethodInfo, typeof(DescriptionAttribute)) as DescriptionAttribute;
            string? responseResult = string.Empty;
            try
            {
                if (!actionContext.ExceptionHandled)
                {
                    if (actionContext.Result != null)
                    {
                        // 检查是否是有效的结果（可进行规范化的结果）
                        if (CheckVaildResult(actionContext.Result, out var data))
                        {
                            responseResult = data?.Json2Str();
                        }
                        //responseResult = responseResult.IsNullOrWhiteSpace() ? ((Microsoft.AspNetCore.Mvc.ContentResult)actionContext.Result).Content : responseResult;
                    }
                }
                else
                    responseResult = "执行出现错误,请查询错误日志.";
            }
            catch (Exception ex)
            {
                responseResult = ex.Message;
            }
            if (_globleActionModels != null && _globleActionModels.Count() != 0 && ExFilterConfigs.FilterOptions.IsDbug)
            {
                string path = context.HttpContext?.Request?.Path.Value?.ToLower();
                if (path.NotNullOrWhiteSpace())
                {
                    path = path.Substring(0, path.LastIndexOf('/'));
                }
                var hasData = _globleActionModels.Where(x => x.Path.ToLower().Contains(path)).FirstOrDefault();
                if (hasData != null)
                {
                    long outTenantId = 0;
                    long.TryParse(httpContext.User?.FindFirstValue(ClaimConst.TENANT_ID), out outTenantId);
                    var sysOpLog = new
                    {
                        Name = descAtt != null ? descAtt.Description : hasData.Description ?? actionDescriptor.ActionName,
                        //OpType = 1,
                        Success = isRequestSucceed ? YesOrNot.Y : YesOrNot.N,
                        Message = isRequestSucceed ? "成功" : "失败",
                        Ip = httpContext.Connection.RemoteIpAddress?.MapToIPv4()?.ToString(),
                        Location = httpRequest.GetRequestUrlAddress(),
                        Browser = clent==null?"":( clent?.UA?.Family + clent?.UA?.Major),
                        Os = clent == null ? "" : (clent?.OS?.Family + clent?.OS?.Major),
                        Url = httpRequest.Path,
                        ClassName = context.Controller.ToString(),
                        MethodName = actionDescriptor.ActionName,
                        ReqMethod = httpRequest.Method,
                        Param = actionArguments,
                        Result = responseResult,// JsonSerializerUtility.Serialize(actionContext.Result),
                        ElapsedTime = sw.ElapsedMilliseconds,
                        OpTime = DateTime.Now,
                        userId = httpContext.User?.FindFirstValue(ClaimConst.CLAINM_USERID),
                        Account = httpContext.User?.FindFirstValue(ClaimConst.CLAINM_ACCOUNT),
                        TenantId = outTenantId
                    };
                    await _eventPublisher.PublishAsync(new ChannelEventSource("Create:OpLog", sysOpLog));
                }
            }

            if (ExFilterConfigs.FilterOptions.IsLogFile)
            {
                StringBuilder strInfo = new StringBuilder();
                strInfo.Append("1. 调试: >> 操作时间: " + DateTime.Now + " \r\n");
                strInfo.Append("2. 地址: " + "Method : " + httpRequest.Method + "  URL：" + httpRequest.GetRequestUrlAddress() + "  \r\n");
                strInfo.Append("3. 传入参数: " + actionArguments + " \r\n");
                strInfo.Append("4. 执行结果: " + responseResult + "  \r\n");
                //strInfo.Append("5. IP地址 : " + context.HttpContext.GetRemoteIpAddressToIPv4() + "    \r\n");
                strInfo.Append("-----------------------------------------------------------------------------------------------------------------------------\r\n");

                LogFactory.Debug(strInfo.ToString());
            }
        }

        // 处理 BadRequestObjectResult 类型规范化处理
        if (actionContext.Result is BadRequestObjectResult badRequestObjectResult)
        {
            // 解析验证消息
            var validationMetadata = ValidatorContext.GetValidationMetadata(badRequestObjectResult.Value);
            var result = OnValidateFailed(context, validationMetadata);
            if (result != null) actionContext.Result = result;
            // 打印验证失败信息
            LogFactory.Error($"Validation Failed:\r\n{validationMetadata.Message}");
        }
        else
        {
            IActionResult result = default;
            // 检查是否是有效的结果（可进行规范化的结果）
            if (CheckVaildResult(actionContext.Result, out var data))
            {
                result = OnSucceeded(actionContext, data);
            }
            // 如果是不能规范化的结果类型，则跳过
            if (result == null) return;
            actionContext.Result = result;
        }
    }

    /// <summary>
    /// 判断是否支持 Mvc 控制器规范化处理
    /// </summary>
    /// <param name="httpContext"></param>
    /// <param name="actionDescriptor"></param>
    /// <returns></returns>
    internal static bool CheckSupportMvcController(HttpContext httpContext, ControllerActionDescriptor actionDescriptor)
    {
        // 如果未启用 MVC 规范化处理，则跳过
        if (typeof(Controller).IsAssignableFrom(actionDescriptor.ControllerTypeInfo)) return false;
        return true;
    }

    /// <summary>
    /// 成功返回值
    /// </summary>
    /// <param name="context"></param>
    /// <param name="data"></param>
    /// <returns>ActionExecutionDelegate</returns>
    public IActionResult OnSucceeded(ActionExecutedContext context, object data)
    {
        return new JsonResult(RESTfulResult(CodeStatus.OK, data: data, message: "请求成功"));
    }

    /// <summary>
    /// 验证失败返回值
    /// </summary>
    /// <param name="context"></param>
    /// <param name="metadata"></param>
    /// <returns></returns>
    public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata)
    {
        //return new JsonResult(RESTfulResult(CodeStatus.BadRequest, message: metadata.ValidationResult));
        return new JsonResult(RESTfulResult(CodeStatus.BadRequest, message: metadata.Message));
    }
    /// <summary>
    /// 返回 RESTful 风格结果集
    /// </summary>
    /// <param name="statusCode"></param>
    /// <param name="data"></param>
    /// <param name="message"></param>
    /// <returns></returns>
    private static RestfulResult<object> RESTfulResult(CodeStatus statusCode, object data = default, object? message = default)
    {
        return new RestfulResult<object>
        {
            Code = statusCode,  // 处理没有返回值情况 204
            Data = data,
            Message = message,
            Extras = string.Empty,
            Timestamp = DateTime.UtcNow.Ticks
        };
    }
    /// <summary>
    /// 检查是否是有效的结果（可进行规范化的结果）
    /// </summary>
    /// <param name="result"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    internal static bool CheckVaildResult(IActionResult result, out object? data)
    {
        data = default;

        // 排除以下结果，跳过规范化处理
        var isDataResult = result switch
        {
            ViewResult => false,
            PartialViewResult => false,
            FileResult => false,
            ChallengeResult => false,
            SignInResult => false,
            SignOutResult => false,
            RedirectToPageResult => false,
            RedirectToRouteResult => false,
            RedirectResult => false,
            RedirectToActionResult => false,
            LocalRedirectResult => false,
            ForbidResult => false,
            ViewComponentResult => false,
            PageResult => false,
            _ => true,
        };

        // 目前支持返回值 ActionResult
        if (isDataResult) data = result switch
        {
            // 处理内容结果
            ContentResult content => content.Content,
            // 处理对象结果
            ObjectResult obj => obj.Value,
            // 处理 JSON 对象
            JsonResult json => json.Value,
            _ => null,
        };

        return isDataResult;
    }

    /// <summary>
    /// 获取验证错误信息
    /// </summary>
    /// <param name="errors"></param>
    /// <returns></returns>
    internal static ValidationMetadata GetValidationMetadata(object errors)
    {
        ModelStateDictionary? _modelState = null;
        Dictionary<string, string[]>? validationResults = null;
        bool IsStr = false;
        // 如果是模型验证字典类型
        if (errors is ModelStateDictionary modelState)
        {
            _modelState = modelState;
            // 将验证错误信息转换成字典并序列化成 Json
            validationResults = modelState.Where(u => modelState[u.Key].ValidationState == ModelValidationState.Invalid)
                    .ToDictionary(u => u.Key, u => modelState[u.Key].Errors.Select(c => c.ErrorMessage).ToArray());
        }
        // 如果是 ValidationProblemDetails 特殊类型
        else if (errors is ValidationProblemDetails validation)
        {
            validationResults = validation.Errors
                .ToDictionary(u => u.Key, u => u.Value.ToArray());
        }
        // 如果是字典类型
        else if (errors is Dictionary<string, string[]> dicResults)
        {
            validationResults = dicResults;
        }
        // 其他类型
        else
        {
            IsStr = true;
            validationResults = new Dictionary<string, string[]>{
                {string.Empty, new[]{errors?.ToString()}}
            };
        }

        return new ValidationMetadata
        {
            ValidationResult = validationResults,
            Message = validationResults.Json2Str(),
            ModelState = _modelState
        };
    }
}

/// <summary>
/// 验证上下文
/// </summary>
internal static class ValidatorContext
{
    /// <summary>
    /// 获取验证错误信息
    /// </summary>
    /// <param name="errors"></param>
    /// <returns></returns>
    internal static ValidationMetadata GetValidationMetadata(object errors)
    {
        ModelStateDictionary _modelState = null;
        Dictionary<string, string[]> validationResults = null;
        bool IsStr = false;
        // 如果是模型验证字典类型
        if (errors is ModelStateDictionary modelState)
        {
            _modelState = modelState;
            // 将验证错误信息转换成字典并序列化成 Json
            validationResults = modelState.Where(u => modelState[u.Key].ValidationState == ModelValidationState.Invalid)
                    .ToDictionary(u => u.Key, u => modelState[u.Key].Errors.Select(c => c.ErrorMessage).ToArray());
        }
        // 如果是 ValidationProblemDetails 特殊类型
        else if (errors is ValidationProblemDetails validation)
        {
            validationResults = validation.Errors
                .ToDictionary(u => u.Key, u => u.Value.ToArray());
        }
        // 如果是字典类型
        else if (errors is Dictionary<string, string[]> dicResults)
        {
            validationResults = dicResults;
        }
        // 其他类型
        else
        {
            IsStr = true;
            validationResults = new Dictionary<string, string[]>{
                {string.Empty, new[]{errors?.ToString()}}
            };
        }
        return new ValidationMetadata
        {
            ValidationResult = validationResults,
            Message = (IsStr == true) ? errors?.ToString() : validationResults.Json2Str(),
            ModelState = _modelState
        };
    }
}
